/*
  The MIT License
  
  Copyright (c) 2010 smath-view project
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:
  
  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/
package pl.smath.renderer.model;

import com.google.gwt.user.client.ui.RootPanel;

import gwt.g2d.client.graphics.Color;
import gwt.g2d.client.graphics.Surface;
import pl.smath.renderer.model.sign.MinusSign;
import pl.smath.renderer.renderer.TermRendererException;
import pl.smath.renderer.utils.Cursor;
import pl.smath.renderer.utils.Rectangle;
import pl.smath.renderer.utils.InteractionSocket;

/**
 * TermView - represents rendered Term.
 * 
 * @author Damian Rodziewicz
 *
 */
public class View {
	//TODO measure symbol width
	
	private final String text;
	private boolean negative = false;
	/**
	 * width and height represent the rectangle
	 * in which the whole view is contained
	 */
	private Rectangle rectangle;
	/**
	 * left bottom position of the rectangle
	 * in which the whole view is contained
	 */
	private Cursor cursor;
	protected MinusSign minusSign;
	protected String font;
	private Double fontHeight;
	/**
	 * the difference between bottom of rectangle and actual Y position
	 */
	private Double baselineOffset = 0d;
	
	/**
	 * Constructor
	 */
	protected View(String text){
		if ((text.length()>0)&&(text.charAt(0)=='-')) {
			this.negative = true;
			this.text = text.substring(1);
		} else this.text = text;
		this.rectangle = new Rectangle();
		this.minusSign = new MinusSign();
		this.cursor = new Cursor();
	}
	
	/**
	 * get the current cursor position
	 * @return cursor
	 */
	public Cursor getCursor() {
		return this.cursor;
	}


	/**
	 * @return the font
	 */
	public String getFont() {
		return this.getFontHeight() + "px " + this.font;
	}
	
	/**
	 * @return the fontHeight
	 */
	public Double getFontHeight() {
		return fontHeight;
	}
	
	/**
	 * get height
	 * @return height
	 */
	public Double getHeight() {
		return this.rectangle.getHeight();
	}
	
	/**
	 * get the view's rectangle
	 * @return rectangle
	 */
	public Rectangle getRectangle() {
		return this.rectangle;
	}
	
	/**
	 * @return text/sign to be drawn
	 */
	public String getText(){
		return text;
	}

	/**
	 * get width
	 * @return width
	 */
	public Double getWidth() {
		return this.rectangle.getWidth();
	}
	
	/**
	 * get the x position
	 * @return x
	 */
	public Double getX() {
		return this.cursor.getX();
	}
	
	/**
	 * get the y position
	 * @return y
	 */
	public Double getY() {
		return this.cursor.getY();
	}
	
	/**
	 * Check if minus should be drawn
	 * @return true if minus should be drawn
	 */
	public boolean isNegative() {
		return negative;
	}
	
	/**
	 * render text at the current position
	 * @param canvas
	 * @throws TermRendererException 
	 */
	public void render(Surface canvas, InteractionSocket socket) throws TermRendererException {
		//TODO exceptions
		if ((this.getFont() == null)||(this.getFontHeight() == null)) throw new TermRendererException();
		if (this.getCursor() == null) throw new TermRendererException();
		
		canvas.setFont(this.getFont());
		if (this.isNegative()) {
			minusSign.render(canvas, this.cursor);
			canvas.fillText(this.getText(), this.cursor.getX() + minusSign.getWidth(), this.cursor.getY());
		} else {
			canvas.fillText(this.getText(), this.cursor.getX(), this.cursor.getY());	
		}
	}

	/**
	 * set the current position
	 * @param cursor
	 */
	public void setCursor(Cursor cursor) {
		this.cursor = cursor;
	}

	/**
	 * @param font the font to set
	 */
	public void setFont(String font) {
		if (font.indexOf("px")!=-1) {
			this.fontHeight = new Double(font.substring(0, font.indexOf("px")));
			this.font = font.substring(font.indexOf("px ")+3);
			this.minusSign.setFont(this.font, this.fontHeight);
			this.minusSign.setSpace(1d);
			
			update();
		} else {
			this.fontHeight = null;
			this.font = null;
		}
	}
	
	/**
	 * @param fontHeight the fontHeight to set
	 */
	public void setFontHeight(Double fontHeight) {
		this.fontHeight = fontHeight;
	}
	
	public void setHeight(Double height) {
		this.rectangle.setHeight(height);
	}
	
	/**
	 * set if the term is negative
	 * @param negative
	 */
	public void setNegative(Boolean negative) {
		this.negative = negative;
	}
	
	
	/**
	 * Set the view's height and width 
	 * @param width
	 * @param height
	 */
	public void setRectangle(Double width, Double height) {
		this.setRectangle(new Rectangle(width, height));
	}
	
	/**
	 * Set the view's height and width 
	 * @param width
	 * @param height
	 */
	public void setRectangle(Integer width, Integer height) {
		this.setRectangle(new Double(width), new Double(height));
	}

	/**
	 * Set rectangle in which the view is contained
	 * @param rectangle
	 */
	public void setRectangle(Rectangle rectangle) {
		this.rectangle = rectangle;
	}

	public void setWidth(Double width) {
		this.rectangle.setWidth(width);
	}
	
	/**
	 * update the view
	 */
	public void update() {
		Surface surface = new Surface();
		RootPanel.get().add(surface);
		surface.setFont(this.getFont());
		
		if (this.isNegative()) {
			rectangle.setWidth(surface.measureText(this.getText()) + this.minusSign.getWidth());
		} else {
			rectangle.setWidth(surface.measureText(this.getText()));
		}
		
		if (this.getFontHeight()!=null) {
			rectangle.setHeight(this.getFontHeight());
		}
		RootPanel.get().remove(surface);
	}

	public void setBaselineOffset(Double baselineOffset) {
		this.baselineOffset = baselineOffset;
	}

	public Double getBaselineOffset() {
		return baselineOffset;
	}
	
}
